package com.squid.cloud.fuel.purchase.web;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.alibaba.fastjson.JSONObject;
import com.squid.cloud.common.dto.UserResult;
import com.squid.cloud.common.util.CollectionUtil;
import com.squid.cloud.common.util.DateUtil;
import com.squid.cloud.common.util.JsonUtils;
import com.squid.cloud.common.util.StringUtils;
import com.squid.cloud.common.web.AppBaseController;
import com.squid.cloud.fuel.purchase.service.DepositOrderService;
import com.squid.cloud.model.entity.DepositOrderEntity;
import com.squid.cloud.model.entity.PayModeEntity;

import lombok.extern.slf4j.Slf4j;

@Controller
@RequestMapping("/deposit")
@Slf4j
public class DepositOrderController extends AppBaseController {
	@Autowired
	private DepositOrderService depositOrderService;
	@Autowired
	private FakeDepositService fakeDepositOrderService;
	@Autowired
	private PayModeService payModeService;

	@Autowired
	private SystemMessgeSender systemMessgeSender;

	@Autowired
	private NewsFlashService newsFlashService;

	@Autowired
	private CustomerAccountService customerAccountService;

	@Autowired
	private PayOrderService payOrderService;

	@Autowired
	private CustomerPasswordService customerPasswordService;
	
	@Autowired
	RechargeCardService rechargeCardService;
	
	@Autowired
	BusinessProperties businessProperties;
	
    @Autowired
    private CustomerHeadService customerHeadService;
	
	/**
	 * @date 2018-06-11
	 * @desc
	 * 		提油卡500测试用户，提供购油页面，同时有每月3000块的94者优惠购油
	 * 		提供接口获取折扣和还可以充值金额，超过该金额即恢复原价
	 *
	 * @param response
	 * @return
	 */
	@GetMapping("/beforepay")
	public Map<String, Object> ajaxBeforeCreateOrder(UserResult user, HttpServletResponse response) {
		UserResult user = (UserResult) WebContext.getCurrentUser();
		Map<String, Object> result = depositOrderService.beforeCreateOrder(user.getPhone(),user.getCustomerId());
		return result;
	}

	/**
	 * 充值
	 *
	 * @param response
	 * @return
	 */
	@PostMapping
	public Map<String, Object> ajaxCreateOrder(@RequestBody DepositOrderEntity order, HttpServletResponse response) {
		// 默认账户
		log.info("充值收到请求参数：充值金额={}，油品标号={}", order.getAmount(), order.getOilNo());
		if (StringUtils.isEmpty(order.getOilNo())) {
			throw new BusinessException("1011", "油品标号必填");
		}
		OilNo oilNo = OilNo.code2OilNo(order.getOilNo());
		if (oilNo == null) {
			throw new BusinessException("1016", "系统不存在该油号，请选择其他油号或联系管理员");
		}
		if (order.getAmount() == null) {
			throw new BusinessException("1012", "充值金额必填");
		}
		if (order.getAmount().longValue() <= 0) {
			throw new BusinessException("1013", "充值金额不能小于等于0");
		}
		DepositRestrict restrict = depositOrderService.getDepositRestrict();
		if (order.getAmount().longValue() > restrict.getMaxAmount().longValue()) {
			throw new BusinessException("1014", "充值金额不能超过最高限额");
		}
		if (order.getAmount().longValue() < restrict.getMinAmount().longValue()) {
			throw new BusinessException("1015", "充值金额不能低于最低限额");
		}
		UserResult user = (UserResult) WebContext.getCurrentUser();
		order.setCustomerId(user.getCustomerId());
		order.setQuickRefueling(QuickRefueling.N);
		depositOrderService.create(order);
		Map<String, Object> result = new HashMap<>();
		result.put("orderNo", order.getOrderNo());
		result.put("status", order.getStatus());
		return result;
	}

	/**
	 * 充值流水
	 *
	 * @param response
	 * @return
	 */
	@GetMapping
	@SearchableDefaults(value = {"markDelete_eq=N"}, merge = true)
	public List<Map<String, Object>> ajaxGetOrder(@Qualifier("s") Searchable searchable, String date,String status, QueryPage queryPage, HttpServletResponse response) {
		UserResult user = (UserResult) WebContext.getCurrentUser();
		searchable.addSearchParam("customerId_eq", user.getCustomerId());
//		searchable.addSearchParam("source_eq", com.xjy.squid.common.constants.Constants.APP);

		//增加查询日期
		if(!StringUtils.isEmpty(date))
		{
			Date begin = DateUtil.parseDate(date, "yyyy-MM");
			Date end = DateUtil.getEndDateOfMonth(begin);
			searchable.addSearchParam("depositDate_gte", begin);
			searchable.addSearchParam("depositDate_lte", end);
		}

		if (StringUtils.isNotEmpty(status)) {
			searchable.addSearchParam("status_eq", status);
			if (status.equals(OrderStatus.WAIT_PAY.getCode())) {
				searchable.addSearchParam("quickRefueling_eq", QuickRefueling.N);
			}
		}
		searchable.addSort(Sort.Direction.DESC, "depositDate");
		Page<DepositOrderEntity> page = depositOrderService.findAll(searchable);
		if (CollectionUtil.isEmpty(page.getContent())) {
			return new ArrayList<Map<String, Object>>();
		}

		// 重新设置分页信息，在AjaxListener中只能在返回类型为Page对象时才能处理分页信息
		queryPage.setTargetPage(page.getNumber() + 1);//第几页
		queryPage.setPageCount(page.getTotalPages());//总页数
		queryPage.setRecordCount(Long.valueOf(page.getTotalElements()).intValue());//总记录数

		List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
		for (DepositOrderEntity o : page.getContent()) {
			Map<String, Object> m = new HashMap<>();
			m.put("amount", o.getAmount());
			m.put("depositDate", o.getDepositDate());
			m.put("oilNo", o.getOilNo());
			m.put("orderNo", o.getOrderNo());
			m.put("payMode", StringUtils.isEmpty(o.getPayMode()) ? "" : o.getPayMode());
			m.put("status", o.getStatus());

			result.add(m);
		}
		return result;
	}
	
	
	/**
	 * 充值待支付列表(微信)
	 * @param response
	 * @return
	 */
	@GetMapping("/list/waitPay")
	@SearchableDefaults(value = {"markDelete_eq=N"}, merge = true)
	public List<Map<String, Object>> ajaxGetWechatOrder(@Qualifier("s") Searchable searchable, QueryPage queryPage, HttpServletResponse response) {
		UserResult user = (UserResult) WebContext.getCurrentUser();
		searchable.addSearchParam("customerId_eq", user.getCustomerId());
		searchable.addSearchParam("source_eq", com.xjy.squid.common.constants.Constants.WECHAT);
		searchable.addSearchParam("status_eq", OrderStatus.WAIT_PAY.getCode());
		searchable.addSearchParam("quickRefueling_eq", QuickRefueling.N);
		searchable.addSort(Sort.Direction.DESC, "depositDate");
		Page<DepositOrderEntity> page = depositOrderService.findAll(searchable);
		if (CollectionUtil.isEmpty(page.getContent())) {
			return new ArrayList<Map<String, Object>>();
		}

		// 重新设置分页信息，在AjaxListener中只能在返回类型为Page对象时才能处理分页信息
		/*queryPage.setTargetPage(page.getNumber() + 1);//第几页
		queryPage.setPageCount(page.getTotalPages());//总页数
		queryPage.setRecordCount(Long.valueOf(page.getTotalElements()).intValue());//总记录数
*/
		List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
		for (DepositOrderEntity o : page.getContent()) {
			Map<String, Object> m = new HashMap<>();
			m.put("amount", o.getAmount());
			m.put("depositDate", o.getDepositDate());
			m.put("orderNo", o.getOrderNo());
			m.put("payMode", StringUtils.isEmpty(o.getPayMode()) ? "" : o.getPayMode());
			m.put("status", o.getStatus());
			result.add(m);
		}
		return result;
	}

	/**
	 * 获取充值金额限制
	 *
	 * @param response
	 * @return
	 */
	@GetMapping("/amount/restrict")
	public Map<String, Object> ajaxAmountRestrict(HttpServletResponse response) {
		DepositRestrict restrict = depositOrderService.getDepositRestrict();
		Map<String, Object> result = new HashMap<>();
		result.put("maxAmount", restrict.getMaxAmount());
		result.put("minAmount", restrict.getMinAmount());
		return result;
	}

	/**
	 * 获取支付方式
	 *
	 * @param response
	 * @return
	 */
	@GetMapping("/paymode")
	public List<Map<String, Object>> ajaxPaymode(HttpServletResponse response) {
		List<Map<String, Object>> result = new ArrayList<>();

		List<PayModeEntity> modes = payModeService.getEnabledPayMode();
		for (PayModeEntity each : modes) {
			Map<String, Object> m = new HashMap<>();
			m.put("payMode", each.getPayMode());
			result.add(m);
		}

		return result;
	}

	/**
	 * 获取购油描述
	 *
	 * @param response
	 * @return
	 */
	@GetMapping("/description")
	public Map<String, Object> ajaxDescription(HttpServletResponse response) {
		String description = depositOrderService.getDepositDescription();
		Map<String, Object> result = new HashMap<>();
		result.put("description", description);
		return result;
	}

	/**
	 * 获取预支付信息
	 *
	 * @param response
	 * @return
	 */
	@PostMapping("/prepay")
	public Map<String, Object> ajaxPrepay(@RequestBody DepositOrderDto order, HttpServletResponse response) {
		if (StringUtils.isEmpty(order.getOrderNo())) {
			throw new BusinessException("1011", "订单号必填");
		}
		if (StringUtils.isEmpty(order.getPayMode())) {
			throw new BusinessException("1011", "支付方式必填");
		}
		log.info("获取预支付信息收到请求，订单号={}，支付方式={}, openid={}", order.getOrderNo(), order.getPayMode(), order.getOpenid());
		UserResult user = (UserResult) WebContext.getCurrentUser();
		order.setCustomerId(user.getCustomerId());
		String prepayInfo = depositOrderService.prepay(order);
		Map<String, Object> result = new HashMap<>();
		result.put("payinfo", prepayInfo);
		return result;
	}
	
	@Autowired
	SinopecGoodDriverOrderService sinopecGoodDriverOrderService;

	/**
	 * 支付成功回调
	 *
	 * @param response
	 */
	@PostMapping("/notify")
	public void ajaxNotify(HttpServletRequest request, HttpServletResponse response) {
		Map<String, Object> reqParam = getNotifyParameters(request);
		log.info("异步回调参数：" + JsonUtils.objectToJson(reqParam));
		PayemntPayNotifyResponse notifyResponse = new PayemntPayNotifyResponse();
		notifyResponse = MapUtils.mapToBean(reqParam, notifyResponse);

		/*BusinessProperties properties = SpringBeanUtils.getBean(BusinessProperties.class);
		boolean isSuccess = YijifuGateway.getOpenApiClientService().verificationSign(JsonUtils.objectToJson(reqParam), properties.getPayment().getKey());
		if (!isSuccess || !notifyResponse.isSuccess()) {
			return;
		}*/

		// 更新订单状态
		try {
			DepositOrderEntity order = new DepositOrderEntity();
			order.setPrepayNo(notifyResponse.getMerchOrderNo());
			if (Constants.PAYMENT_TRADE_FAIL.equals(notifyResponse.getTradeStatus())) {
				order.setStatus(OrderStatus.FAIL.getCode());
				depositOrderService.updateOrderByPrepayNoWhenNotify(order);
			} else if (Constants.PAYMENT_TRADE_SUCCESS.equals(notifyResponse.getTradeStatus())) {
				if (notifyResponse.getTradeType().equals(Constants.ALI_APP_PAY)) {
					order.setPayMode(PayMode.ALIPAY.getCode());
				} else if (notifyResponse.getTradeType().equals(Constants.WECHAT_APP_PAY)) {
					order.setPayMode(PayMode.WECHAT.getCode());
				} else if (notifyResponse.getTradeType().equals(Constants.WECHAT_H5_PAY)) {
					order.setPayMode(PayMode.WECHATH5PAGE.getCode());
				}
				order.setPayNo(notifyResponse.getTradeNo());
				order.setStatus(OrderStatus.SUCCESS.getCode());
				depositOrderService.updateOrderByPrepayNoWhenNotify(order);
			} else {
				return;
			}
		} catch (Exception e) {
			log.error("回调更新订单状态失败", e);
		}

		DepositOrderEntity depositOrder = depositOrderService.findByPrepayNo(notifyResponse.getMerchOrderNo());
		
		// 若用户为平安车点点用户，并且充值金额大于100，并且为本月唯一充值，那么将赠送60的邮费
		depositOrderService.fakePingAnChediandianGift(depositOrder);
		
		// 好车主快速支付加油
		boolean quick = false;
		Object obj = CacheManage.getInstance().getAttributeObj(SinopecGoodDriverOrderService.AUTH_CODE_ORDERNO_REDIS_PREFIX+depositOrder.getOrderNo());
		if(obj != null){
			JSONObject json = JSONObject.parseObject(obj.toString());
			SinopecGoodDriverOrderQuickPayRequestDto quickPayRequest = JSONObject.toJavaObject(json, SinopecGoodDriverOrderQuickPayRequestDto.class);
			sinopecGoodDriverOrderService.quickPay(quickPayRequest, depositOrder);
			quick = true;
		}
		
		if (depositOrder.getQuickRefueling().equals(QuickRefueling.Y)
				&& OrderStatus.SUCCESS.getCode().equals(depositOrder.getStatus())) {
			if(!quick){
				try {
					PayOrderEntity payOrder = payOrderService.getOrderByNo(depositOrder.getRefuelingOrderNo());
					// CustomerPasswordBizBean password =
					// customerPasswordService.queryByCustomerId(payOrder.getOpenId());
					OrderPayRequest req = new OrderPayRequest();
					// req.setPayPwd(password.getPassword());
					req.setPayFee(payOrder.getPayFee());
					req.setLat(payOrder.getStationLat());
					req.setLon(payOrder.getStationLon());
					req.setCouponId(payOrder.getCouponId());
					req.setDisAccountId(payOrder.getDisAccountId());
					log.info("快捷加油时购油成功后请求加油接口请求参数：{}", JsonUtils.objectToJson(req));
					payOrderService.payingOrder(payOrder.getOpenId(), payOrder.getOrderNo(), req);
				} catch (SquidPayException e) {
					log.error("快捷加油发起余额支付鱿鱼儿支付异常", e);
				} catch (Exception e) {
					log.error("快捷加油发起余额支付发生异常", e);
				}
			}
		} else {
			//APP时才发送消息（短信与快讯）
			if(com.xjy.squid.common.constants.Constants.APP.equals(depositOrder.getSource())){
				// 发送购油成功消息给用户
				try {
					if (Constants.PAYMENT_TRADE_SUCCESS.equals(notifyResponse.getTradeStatus())) {
						SystemMessgeSender.SystemMessage type = SystemMessgeSender.SystemMessage.DepositSuccess;
						//DepositOrderEntity order = depositOrderService.findByPrepayNo(notifyResponse.getMerchOrderNo());
						CustomerAccountEntity account = customerAccountService.queryAccountByOilNo(depositOrder.getCustomerId(), OilNo.code2OilNo(depositOrder.getOilNo()));
						String userId = depositOrder.getCustomerId();
						Map<String, String> map = new HashMap<>();
						map.put("finishTime", DateUtil.formatDate(DateUtil.now(), "yyyy-MM-dd HH:mm:dd"));
						map.put("orderNo", depositOrder.getOrderNo());
						map.put("account", OilNo.code2OilNo(depositOrder.getOilNo()).getDisplayName());
						map.put("amount", Money.cent(depositOrder.getAmount()).getAmount().toString());
						map.put("accountBalance", Money.cent(account.getBalance()).getAmount().toString());
						systemMessgeSender.send(type, userId, map);
					}
				} catch (Exception e) {
					log.error("发送购油成功消息给用户失败", e);
				}

				//发送购油成功快讯
				try {
					if (Constants.PAYMENT_TRADE_SUCCESS.equals(notifyResponse.getTradeStatus())) {
						//DepositOrderEntity order = depositOrderService.findByPrepayNo(notifyResponse.getMerchOrderNo());
						NewsFlashBizBean flash = new NewsFlashBizBean();
						//138****6365用户14:25在鱿鱼购油￥10000元
						StringBuffer content = new StringBuffer();
						content.append(maskPhoneNo(depositOrder.getPhoneNo()));
						content.append("用户");
						content.append(DateUtil.formatDate(depositOrder.getDepositDate(), "HH:mm"));
						content.append("在鱿鱼购油￥");
						content.append(Money.cent(depositOrder.getAmount()).getAmount().toString());
						content.append("元");
						flash.setContent(content.toString());
						newsFlashService.addNewsFlash(flash);
					}
				} catch (Exception e) {
					log.error("发送购油成功快讯失败", e);
				}
			}
		}

		ResponseUtils.writeXml(response, "success");
	}

	/**
	 * 后台订单上账支付异步通知
	 *
	 * @param response
	 */
	@PostMapping("/fake/notify")
	public void ajaxFakeNotify(HttpServletRequest request, HttpServletResponse response) {
		Map<String, Object> reqParam = getNotifyParameters(request);
		log.info("异步回调参数：" + JsonUtils.objectToJson(reqParam));
		PayemntPayNotifyResponse notifyResponse = new PayemntPayNotifyResponse();
		notifyResponse = MapUtils.mapToBean(reqParam, notifyResponse);

		BusinessProperties properties = SpringBeanUtils.getBean(BusinessProperties.class);
		boolean isSuccess = YijifuGateway.getOpenApiClientService().verificationSign(JsonUtils.objectToJson(reqParam), properties.getPayment().getKey());
		if (!isSuccess || !notifyResponse.isSuccess()) {
			return;
		}

		// 更新订单状态
		try {
			FakeDepositOrderEntity order = new FakeDepositOrderEntity();
			order.setOrderNo(notifyResponse.getMerchOrderNo());
			if (Constants.PAYMENT_TRADE_FAIL.equals(notifyResponse.getTradeStatus())) {
				order.setStatus(OrderStatus.FAIL.getCode());
				fakeDepositOrderService.updateOrder(order);
			} else if (Constants.PAYMENT_TRADE_SUCCESS.equals(notifyResponse.getTradeStatus())) {
				order.setStatus(OrderStatus.SUCCESS.getCode());
				fakeDepositOrderService.updateOrder(order);
			} else {
				return;
			}
		} catch (Exception e) {
			log.error("回调更新订单状态失败", e);
		}
		ResponseUtils.writeXml(response, "success");
	}

	private String maskPhoneNo(String phoneNo) {
		StringBuffer masked = new StringBuffer();
		masked.append(phoneNo.substring(0, 3) + "****" + phoneNo.substring(phoneNo.length() - 4));
		return masked.toString();
	}

	public static Map<String, Object> getNotifyParameters(HttpServletRequest request) {
		Map<String, Object> params = new TreeMap<>();
		Enumeration<String> enumeration = request.getParameterNames();
		while (enumeration.hasMoreElements()) {
			String name = enumeration.nextElement();
			String[] values = request.getParameterValues(name);
			if (values == null || values.length == 0) {
				continue;
			}
			Object value = null;
			if ("true".equals(values[0])) {
				value = true;
			} else if ("false".equals(values[0])) {
				value = false;
			} else {
				value = values[0];
			}
			// 注意：这里是判断不为null,没有包括空字符串的判断。
			if (value != null) {
				params.put(name, value);
			}
		}
		return params;
	}

	/**
	 * 删除待支付订单
	 *
	 * @param order
	 * @param response
	 * @return
	 */
	@PostMapping("/waitpay/deletion")
	public String ajaxWaipayDeletion(@RequestBody DepositOrderEntity order, HttpServletResponse response) {
		depositOrderService.deleteWaitpayOrder(order);
		return SUCCESS_MESSAGE;
	}

	/**
	 * 获取油品编号
	 *
	 * @param response
	 * @return
	 */
	@GetMapping("/oilno")
	public List<Map<String, Object>> ajaxOilno(HttpServletResponse response) {
		List<Map<String, Object>> result = new ArrayList<>();
		for (OilNo no : OilNo.values()) {
			if(no.isVisible()){
				Map<String, Object> map = new HashMap<>();
				map.put("code", no.getCode());
				map.put("displayName", no.getDisplayName());
				map.put("visible", no.isVisible());
				result.add(map);
			}
		}
		return result;
	}
	
	

	
	/**
	 * @date	2018-04-19
	 * @desc	充值卡充值
	 * 			用户输入卡号和密码进行充值卡激活业务
	 * @param response
	 * @param chargeRequest
	 * @return
	 */
	@PostMapping("/couponrecharge")
	@ResponseBody
	public CouponRechargeResponseDto couponRecharge(HttpServletResponse response, @RequestBody CouponRechargeRequestDto chargeRequest) {
		CouponRechargeResponseDto resultDto = new CouponRechargeResponseDto();
		UserResult user = (UserResult) WebContext.getCurrentUser(); 
		log.info("用户customerId:[{}]，使用充值卡进行充值，充值卡信息为:[{}]", user.getCustomerId(), chargeRequest);
		try {
			String key = "couponrecharge:"+user.getCustomerId();
			Object errNumObj = CacheManage.getInstance().getAttributeObj(key);
			Integer errNum = 0;
			if(errNumObj != null){
				errNum = (Integer) errNumObj;
			}
			if(errNum < businessProperties.getCouponrecharge().getCharge_err_num()){
				resultDto = rechargeCardService.couponRecharge(chargeRequest, user.getCustomerId());
				log.info("用户customerId:[{}]，使用充值卡进行充值，充值卡信息为:[{}] 调用充值服务结果为:[{}]", user.getCustomerId(), chargeRequest, resultDto);
				if("100".equals(resultDto.getMsgcode())){
					// 处理成功
					CacheManage.getInstance().removeAttribute(key);
				} else {
					// 处理失败
					errNum++;
					CacheManage.getInstance().setAttributeObj(key, errNum, getTodayRestMilliSerconds());
					if("12".equals(resultDto.getMsgcode()))
					{
						//nothing
					}
					else
					{
						int remainCount = businessProperties.getCouponrecharge().getCharge_err_num() - errNum;
						resultDto.setMsg("卡密错误，您还可输入"+ remainCount +"次");
					}
				}
			} else {
				resultDto = new CouponRechargeResponseDto("今日错误次数已达上限", "99");
			}
		} catch (PayTimeOutException | Exception e) {
			e.printStackTrace();
			resultDto = new CouponRechargeResponseDto("卡充值出现异常!", "99");
		}
		log.info("用户customerId:[{}]，使用充值卡进行充值，充值卡信息为:[{}] 充值结果为:[{}]", user.getCustomerId(), chargeRequest, resultDto);
		return resultDto;
	}
	
	public static long getTodayRestMilliSerconds(){
		Calendar c = Calendar.getInstance();
		long now = c.getTimeInMillis();
		c.add(Calendar.DAY_OF_MONTH, 1);
		c.set(Calendar.HOUR_OF_DAY, 0);
		c.set(Calendar.MINUTE, 0);
		c.set(Calendar.SECOND, 0);
		c.set(Calendar.MILLISECOND, 0);
		long millis = c.getTimeInMillis() - now;
		return millis;
	}
	
}
